package edu.upol.paradise.compiler.types;

public abstract class ParadiseNumber implements ParadiseObject {

	public boolean isTrue() {
		return true;
	}

	public boolean isAtom() {
		return true;
	}
	
	private static enum Operation { ADD, SUB, MUL, DIV }
	
	private static ParadiseNumber operation(Operation operation, double startingValue, ParadiseObject...numbers){
		boolean isFloat = false;
		double res = startingValue;
		for (ParadiseObject numberCandidate : numbers){
			ParadiseNumber number = (ParadiseNumber)numberCandidate;
			if (!isFloat && number instanceof ParadiseFloat){
				isFloat = true;
			}
			switch (operation){
			case ADD:
				res += number.floatValue();
				break;
			case DIV:
				res /= number.floatValue();
				break;
			case MUL:
				res *= number.floatValue();
				break;
			case SUB:
				res -= number.floatValue();
				break;
			
			}
		}
		return isFloat ? new ParadiseFloat(res) : new ParadiseFixnum((int) res);
	}
	
	public static ParadiseNumber add(ParadiseObject... numbers){
		return operation(Operation.ADD, 0, numbers);
	}
	
	public static ParadiseNumber sub(ParadiseObject... numbers){
		if (numbers.length == 1)
			return operation(Operation.SUB, 0, numbers);
		else{
			ParadiseObject[] arrCopy = new ParadiseObject[numbers.length-1];
			for (int i=1; i<numbers.length; i++)
				arrCopy[i-1] = numbers[i];
			return operation(Operation.SUB, ((ParadiseNumber) numbers[0]).floatValue(), arrCopy);
		}
	}
	
	public static ParadiseNumber mul(ParadiseObject... numbers){
		return operation(Operation.MUL, 1, numbers);
	}
	
	public static ParadiseNumber div(ParadiseNumber n1, ParadiseObject... numbers){
		ParadiseObject[] arrCopy = new ParadiseObject[numbers.length+1];
		arrCopy[0] = n1;
		for (int i=0; i<numbers.length; i++)
			arrCopy[i+1] = numbers[i];
		return operation(Operation.DIV, 1, arrCopy);
	}

	protected abstract double floatValue();

	public static ParadiseObject sqrt(ParadiseNumber data) {
		return new ParadiseFloat(Math.sqrt(data.floatValue()));
	}
	
}
